package nets

import (
	"errors"
	"net"
	"strings"
)

func ParseIPAddr(s string) ([]string, error) {
	var addrs []string

	// ip address
	trimmedAddr := strings.TrimSpace(s)
	if s == "" {
		return nil, errors.New("empty address")
	}
	ip := net.ParseIP(trimmedAddr)
	if ip != nil { // valid ip
		addrs = append(addrs, ip.String())
		return addrs, nil
	}

	// ip net
	ip, ipnet, err := net.ParseCIDR(trimmedAddr)
	if err == nil && ipnet != nil {
		for ip := ip.Mask(ipnet.Mask); ipnet.Contains(ip); IncrementIP(ip) {
			addrs = append(addrs, ip.String())
		}
		return addrs, nil
	}

	// host
	hosts, err := net.LookupHost(s)
	if err != nil {
		return addrs, err
	}

	for _, host := range hosts {
		ipa, err := net.ResolveIPAddr("ip", host)
		if err != nil {
			return addrs, errors.New("query host ip addr failed")
		}

		if ipa.IP.To4() != nil {
			addrs = append(addrs, ipa.String())
			break
		}
	}

	if len(addrs) == 0 {
		return nil, errors.New("no valid ip address")
	}

	return addrs, nil
}

func IncrementIP(ip net.IP) {
	for i := len(ip) - 1; i >= 0; i-- {
		ip[i]++
		if ip[i] != 0 {
			break
		}
	}
}

func LookupLocalAddrByRoute(s string) (net.IP, error) {
	conn, err := net.Dial("udp", s+":80")
	if err != nil {
		return nil, err
	}
	defer conn.Close()

	return conn.LocalAddr().(*net.UDPAddr).IP, nil
}
